﻿#include <QDateTime>
#include <QDir>
#include <memory>
#include <iostream>
#include <QStandardPaths>

#include "Logger.h"

#ifdef Q_OS_LINUX
QString Logger::m_logPath = "/home/adt/data/cvvision/logs";
#else
QString Logger::m_logPath = "./logs";
#endif

QMutex g_mutex;
Logger::Logger(QObject *parent)
    : QThread(parent)
{
    QDir dir;
    if (!dir.exists(m_logPath)) {
        dir.mkpath(m_logPath);
    }

    start();
}

Logger::~Logger()
{
    exitThread();

    printf("Logger destroyd\n");
}

Logger *Logger::instance()
{
    static Logger logger;
    return &logger;
}

void Logger::messageWrapper(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QString t;
    switch (type) {
    case QtDebugMsg:
        t = "debug   ";
        break;
    case QtInfoMsg:
        t = "info    ";
        break;
    case QtWarningMsg:
        t = "warning ";
        break;
    case QtCriticalMsg:
        t = "critical";
        break;
    case QtFatalMsg:
        t = "fatal   ";
        break;
    }
    QString log, fn;
    {
        QMutexLocker locker(&g_mutex);
        QDateTime dt = QDateTime::currentDateTime();
        fn = QString(context.file);
        log = QString("[%1 %2 %3][%4:%5]: | %6")
                .arg(dt.time().toString("hh:mm:ss:zzz"))
                .arg(t)
                .arg(QString::number(reinterpret_cast<qint64>(QThread::currentThreadId()), 16).toUpper())
                .arg(fn.mid(fn.lastIndexOf("/") + 1))
                .arg(context.line)
                .arg(msg);
    }

    std::cout << log.toLocal8Bit().data() << std::endl;

    write(type, fn.mid(fn.lastIndexOf("/") + 1), log, msg);

    // wait log thread to written all log message
    if (type == QtFatalMsg) {
        QThread::sleep(1);
    }
}

void Logger::setLogSavePath(const QString &path)
{
    m_logPath = path;
}

void Logger::write(QtMsgType type, const QString &fileName, const QString &log, const QString &msg)
{
    instance()->add(log);

    instance()->newMessage((int)type, fileName, log);
//    emit instance()->sigMessage(log);

    if (type == QtCriticalMsg) {
        instance()->critical(msg);
    }
}

void Logger::exitThread()
{
    m_enable = false;
    if (isRunning())
    {
        m_hasTask.wakeAll();
        quit();
        wait(100);
    }
    printf("Logger exitThread\n");
}

void Logger::run()
{
    while (m_enable) {

        QString text;

        {
            QMutexLocker locker(&m_mutex);
            if (m_waitBuffer.isEmpty())
            {
                m_hasTask.wait(&m_mutex);
            }

            if (m_waitBuffer.isEmpty())
            {
                printf("log thread exit\n");
                break;  // destructor called
            }

            text = m_waitBuffer.takeFirst();
        }

        QFile f(m_logPath + QString("/%1.log").arg(QDateTime::currentDateTime().toString("yyyyMMdd-HH")));
        if (f.open(QFile::WriteOnly | QFile::Append | QFile::Text)) {
            f.write(text.toLocal8Bit());
            f.write("\n");
            f.close();
        } else {
            printf("ERORRRRRRRRR write log faild, log file can not open\n");
        }
    }

    printf("log thread exit222\n");
    while (!m_waitBuffer.isEmpty()) {
        QString text = m_waitBuffer.takeFirst();
        QFile f(m_logPath + QString("/%1.log").arg(QDateTime::currentDateTime().toString("yyyyMMdd-HH")));
        if (f.open(QFile::WriteOnly | QFile::Append | QFile::Text)) {
            f.write(text.toLocal8Bit());
            f.write("\n");
            f.close();
        } else {
            printf("ERORRRRRRRRR write log faild, log file can not open\n");
        }
    }
}

void Logger::add(const QString &text)
{
    if (!m_enable)
    {
        return;
    }

    m_mutex.lock();
    m_waitBuffer.append(text);
    m_hasTask.wakeAll();
    m_mutex.unlock();
}

